library(modplots)
library(tidyverse)
library(Seurat)
library(plotly)
# Mitochondrial genes
mt <- c("ENSGALG00000035334", #COX3
        "ENSGALG00000032456", #COII
        "ENSGALG00000032142", #MT-CO1
        "ENSGALG00000032079", #MT-CYB
        "ENSGALG00000037838", #ND6
        "ENSGALG00000029500", #ND5
        "ENSGALG00000036229", #MT-ND4
        "ENSGALG00000042478", #ND4L
        "ENSGALG00000030436", #ND3
        "ENSGALG00000041091", #MT-ATP6
        "ENSGALG00000032465", #MT-ATP8
        "ENSGALG00000043768", #MT-ND2
        "ENSGALG00000042750") #MT-ND1

# volcanoplot thresholds
p.adj <- 0.05
l2fc <- 0.5

B10-L10-int

# seurat object
my.se <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_lumb_int_seurat_250723.rds")
# cluster labels from B10int and L10int
ctrl_lumb_int_combined_labels <- readRDS("~/spinal_cord_paper/annotations/ctrl_lumb_int_combined_labels.rds")

identical(colnames(my.se), rownames(ctrl_lumb_int_combined_labels))
[1] TRUE
my.se$annot_sample  <- ctrl_lumb_int_combined_labels$annot_sample

my.se@active.assay <- "RNA"

intra cluster DE analysis

We do DE analysis per cluster, contrasting B10 and L10 samples:

markers <- list()
numbers <- list()
composition <-list()

for (i in seq(levels(Idents(my.se)))) {
  # subset for individual clusters
  mn.se <- subset(x = my.se, idents = levels(Idents(my.se))[i])
  mn.se$sample <- str_extract(mn.se$orig.ident, "ctrl|lumb")
  
  composition[[i]] <- mn.se[[]] %>% 
    select(sample, annot_sample)
  
  Idents(mn.se) <- "sample"
  
  tmp_markers <- FindMarkers(mn.se,
                             ident.1 = "ctrl",
                             only.pos = FALSE, 
                             min.pct = 0.25, 
                             logfc.threshold =  0.2,
                             latent.vars = c("CC.Difference.seurat"), 
                             test.use = "MAST", 
                             assay = "RNA")
  # cell numbers per sample
  numbers[[i]] <- data.frame(table(mn.se$sample))
  
  tmp_markers <- tmp_markers %>%
    rownames_to_column("Gene.stable.ID") %>% 
    left_join(gnames)
  
  markers[[i]] <- tmp_markers
}

names(markers) <- paste0("cl-", levels(Idents(my.se)))
names(numbers) <- paste0("cl-", levels(Idents(my.se)))
names(composition) <- paste0("cl-", levels(Idents(my.se)))

# bind lists into data frames
lumb_markers <- bind_rows(markers, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))
lumb_numbers <- bind_rows(numbers, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))
lumb_composition <- bind_rows(composition, .id = "cluster") %>% 
  mutate(cluster = factor(cluster, levels = paste0("cl-", levels(Idents(my.se)))))

saveRDS(lumb_markers, "~/spinal_cord_paper/data/Gg_ctrl_lumb_int_markers.rds")
saveRDS(lumb_numbers, "~/spinal_cord_paper/data/Gg_ctrl_lumb_int_numbers.rds")
saveRDS(lumb_composition, "~/spinal_cord_paper/data/Gg_ctrl_lumb_int_composition.rds")
# load the DE data
lumb_markers <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_lumb_int_markers.rds") %>% 
  mutate(clust_id = str_remove(cluster, "^cl-"))
lumb_numbers <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_lumb_int_numbers.rds") %>% 
  mutate(clust_id = str_remove(cluster, "^cl-"))
lumb_composition <- readRDS("~/spinal_cord_paper/data/Gg_ctrl_lumb_int_composition.rds") %>% 
  mutate(clust_id = str_remove(cluster, "^cl-"))

Plot the cluster compositions and the number of marker genes.


DimPlot(my.se, label = TRUE, reduction = "tsne")


ggplot(data = lumb_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 3) +
  geom_text(nudge_y = 50, size = 3) +
  ggtitle("Cluster composition by sample (nCells)")


ggplot(data = lumb_markers %>% filter(p_val_adj < 0.05 & avg_log2FC > 0.5), aes(x = cluster, group = cluster)) +
  geom_bar() +
  facet_wrap("cluster", nrow = 3,scales = "free_x") +
  ggtitle("Number of sig. DE genes")

NA
NA
NA

DA clusters from miloR

We select the clusters with the highest amount of neighbourhoods with DA of cells. Those are clusters 3 (neurons), 21, 22 (Glycogen body), and 30 motor neurons.

# vector of clusters
select_clusters <- c(3,21,22,30)

select_lumb_markers <- filter(lumb_markers, clust_id %in% select_clusters)
select_lumb_numbers <- filter(lumb_numbers, clust_id %in% select_clusters)
select_lumb_composition <- filter(lumb_composition, clust_id %in% select_clusters)

Barplots

Barplots showing number of cells from B10 or L10, and the contributions from the individual B10int and L10int clusters:

ggplot(data = select_lumb_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 1) +
  geom_text(nudge_y = 10) +
  ggtitle("Cluster composition by sample (nCells)")

toplot <- select_lumb_composition %>% 
  mutate(annot_sample = str_extract(annot_sample, "\\d{1,2}_.{1}(?=trl|umb)")) %>% 
  mutate(annot_sample = factor(annot_sample)) %>% 
  group_by(sample, cluster) %>%
  count(annot_sample) %>% 
  mutate(label_ypos = cumsum(n)- 0.5*n)

BL_select_barplot <- ggplot(data=toplot, aes(x=sample, y=n, fill=fct_rev(annot_sample))) +
  geom_bar(stat="identity", color = "black") +
  geom_text(aes(y=label_ypos, label=annot_sample), 
            color="black", size=3.5) +
  facet_wrap("cluster", nrow = 1) +
    theme(legend.position="none") +
  ggtitle("BL10int cluster contributions")

BL_select_barplot

pdf("~/spinal_cord_paper/figures/Fig_4_BL10int_high_DA_clust_contribution.pdf")
BL_select_barplot
dev.off()
png 
  2 

Volcanoplots

toplot <- select_lumb_markers %>% 
  mutate(gene_type = case_when(
    avg_log2FC >= 0.5 & p_val_adj <= 0.05 ~ "ctrl",
    avg_log2FC <= -0.5 & p_val_adj <= 0.05 ~ "lumb",
    TRUE ~ "ns")
  )

cols <- c(ctrl = "black",
          lumb = "#419c73",
          ns = "grey")

shapes <- c(ctrl = 21,
            lumb = 21,
            ns = 20)

volplot <- ggplot(data = toplot,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  facet_wrap("cluster", nrow = 1) +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes")

volplot

# ggplotly(volplot, width = 1000, height = 600)

Plots without HOX and mitochondrial genes:

# filter out HOX and MT genes
toplot_nomt <- toplot %>% 
  filter(!grepl("^HOX", Gene.name)) %>% 
  filter(!Gene.stable.ID %in% mt)

volplot_nomt <- ggplot(data = toplot_nomt,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  facet_wrap("cluster", nrow = 1) +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes (without MT and HOX genes")

volplot_nomt

# ggplotly(volplot_nomt, width = 1000, height = 600)
volplot_nomt +
    ggrepel::geom_text_repel(aes(label = ifelse(gene_type == 'ns',
                                                NA,
                                                Gene.name)),
                             size = 3,
                             color = "black")
Warning: Removed 8233 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 6 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 208 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 534 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 52 unlabeled data points (too many overlaps). Consider increasing max.overlaps

No MN DE genes

Cluster 30 (Consisting of 161 B10 vs 13 L10 cells) shows no MN related markers. Seemingly, those 13 cells are indeed motor neurons. This is supported by the fact of their expression of TUBB3, FOXP1, and SLC18A3.

# Motor neuron cluster
mn.se <- subset(x = my.se, idents = 30)
mn.se$sample <- str_extract(mn.se$orig.ident, "ctrl|lumb")

mn.se@active.assay <- "integrated"

mn_markers <- gnames[grepl("TUBB3|FOXP1|SLC18A3", gnames$Gene.name),]
mn_markers

VlnPlot(mn.se, group.by = "sample", mn_markers$Gene.stable.ID, cols = c("darkgrey", "#419c73"))

Low DA clusters from miloR

In contrast to the clusters above, we now select clusters 17, 18, and 19. The show a very low amount of DA neighbourhoods, are of similar size and represent neuronal, MFOL, and NPC populations.

# vector of MFOL clusters
low_clusters <- c(17, 18, 19)

low_lumb_markers <- filter(lumb_markers, clust_id %in% low_clusters)
low_lumb_numbers <- filter(lumb_numbers, clust_id %in% low_clusters)
low_lumb_composition <- filter(lumb_composition, clust_id %in% low_clusters)

Barplots

Barplots showing number of cells from B10 or L10, and the contributions from the individual B10int and L10int clusters:

ggplot(data = low_lumb_numbers, aes(x = Var1, y = Freq, group = cluster, label = Freq)) +
  geom_col() +
  facet_wrap("cluster", nrow = 1) +
  geom_text(nudge_y = 10) +
  ggtitle("Cluster composition by sample (nCells)")

toplot <- low_lumb_composition %>% 
  mutate(annot_sample = str_extract(annot_sample, "\\d{1,2}_.{1}(?=trl|umb)")) %>% 
  mutate(annot_sample = factor(annot_sample)) %>% 
  group_by(sample, cluster) %>%
  count(annot_sample) %>% 
  mutate(label_ypos = cumsum(n)- 0.5*n)

BL_low_barplot <- ggplot(data=toplot, aes(x=sample, y=n, fill=fct_rev(annot_sample))) +
  geom_bar(stat="identity", color = "black") +
  geom_text(aes(y=label_ypos, label=annot_sample), 
            color="black", size=3.5) +
  facet_wrap("cluster", nrow = 1) +
    theme(legend.position="none") +
  ggtitle("From which clusters do cells come?")

BL_low_barplot

pdf("~/spinal_cord_paper/figures/Fig_4_BL10int_low_DA_clust_contribution.pdf")
BL_low_barplot
dev.off()
png 
  2 

Volcanoplots

toplot <- low_lumb_markers %>% 
  mutate(gene_type = case_when(
    avg_log2FC >= 0.5 & p_val_adj <= 0.05 ~ "ctrl",
    avg_log2FC <= -0.5 & p_val_adj <= 0.05 ~ "lumb",
    TRUE ~ "ns")
  )

cols <- c(ctrl = "black",
          lumb = "#419c73",
          ns = "grey")

shapes <- c(ctrl = 21,
            lumb = 21,
            ns = 20)

volplot <- ggplot(data = toplot,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  xlim(c(-3.5, 3.5)) +
  facet_wrap("cluster", nrow = 1) +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes")

volplot

# ggplotly(volplot, width = 800, height = 500)

Plots without HOX and mitochondrial genes:

# filter out HOX and MT genes
toplot_nomt <- toplot %>% 
  filter(!grepl("^HOX", Gene.name)) %>% 
  filter(!Gene.stable.ID %in% mt)

volplot_nomt <- ggplot(data = toplot_nomt,
                  aes(x = avg_log2FC,
                      y = -log10(p_val_adj),
                      label = Gene.name,
                      color = gene_type,
                      shape = gene_type
                  )) +
  geom_point() +
  geom_hline(yintercept = -log10(p.adj), linetype = "dashed") +
  geom_vline(xintercept = c(-l2fc,l2fc), linetype = "dashed") +
  scale_color_manual(values = cols) +
  scale_shape_manual(values = shapes) +
  xlim(c(-1.5, 1.5)) +
  facet_wrap("cluster", nrow = 1, scales = "free_y") +
  ylab("-log10(padj)") +
  theme_bw()+
  ggtitle("Sig. marker genes (without MT and HOX genes)")

volplot_nomt

# ggplotly(volplot_nomt, width = 800, height = 500)
p1 <- volplot +
    ggrepel::geom_text_repel(aes(label = ifelse(gene_type == 'ns',
                                                NA,
                                                Gene.name)),
                             size = 3,
                             color = "black")

p2 <- volplot_nomt +
    ggrepel::geom_text_repel(aes(label = ifelse(gene_type == 'ns',
                                                NA,
                                                Gene.name)),
                             size = 3,
                             color = "black")

p1
Warning: Removed 1289 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 11 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 15 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 34 unlabeled data points (too many overlaps). Consider increasing max.overlaps

p2
Warning: Removed 1264 rows containing missing values or values outside the scale range (`geom_text_repel()`).
pdf("~/spinal_cord_paper/figures/Fig_4_BL10int_low_DA_volplots.pdf", width = 8, height = 4)
p1
Warning: Removed 1289 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 16 unlabeled data points (too many overlaps). Consider increasing max.overlaps
Warning: ggrepel: 35 unlabeled data points (too many overlaps). Consider increasing max.overlaps
p2
Warning: Removed 1264 rows containing missing values or values outside the scale range (`geom_text_repel()`).
Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider increasing max.overlaps
dev.off()
png 
  2 

# Date and time of Rendering
Sys.time()

sessionInfo()
LS0tCnRpdGxlOiAiQjEwLUwxMC1pbnQgYW5kIEIxMC1QMTAtaW50IERFIChuZXVyb25zKSIKYXV0aG9yOiAiRmFiaW8gU2FjaGVyIgpkYXRlOiAiMDMuMDkuMjAyNCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogOAplZGl0b3Jfb3B0aW9uczoKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3IgbGlicmFyaWVzfQpsaWJyYXJ5KG1vZHBsb3RzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkocGxvdGx5KQpgYGAKCmBgYHtyIHNldHVwfQojIE1pdG9jaG9uZHJpYWwgZ2VuZXMKbXQgPC0gYygiRU5TR0FMRzAwMDAwMDM1MzM0IiwgI0NPWDMKICAgICAgICAiRU5TR0FMRzAwMDAwMDMyNDU2IiwgI0NPSUkKICAgICAgICAiRU5TR0FMRzAwMDAwMDMyMTQyIiwgI01ULUNPMQogICAgICAgICJFTlNHQUxHMDAwMDAwMzIwNzkiLCAjTVQtQ1lCCiAgICAgICAgIkVOU0dBTEcwMDAwMDAzNzgzOCIsICNORDYKICAgICAgICAiRU5TR0FMRzAwMDAwMDI5NTAwIiwgI05ENQogICAgICAgICJFTlNHQUxHMDAwMDAwMzYyMjkiLCAjTVQtTkQ0CiAgICAgICAgIkVOU0dBTEcwMDAwMDA0MjQ3OCIsICNORDRMCiAgICAgICAgIkVOU0dBTEcwMDAwMDAzMDQzNiIsICNORDMKICAgICAgICAiRU5TR0FMRzAwMDAwMDQxMDkxIiwgI01ULUFUUDYKICAgICAgICAiRU5TR0FMRzAwMDAwMDMyNDY1IiwgI01ULUFUUDgKICAgICAgICAiRU5TR0FMRzAwMDAwMDQzNzY4IiwgI01ULU5EMgogICAgICAgICJFTlNHQUxHMDAwMDAwNDI3NTAiKSAjTVQtTkQxCgojIHZvbGNhbm9wbG90IHRocmVzaG9sZHMKcC5hZGogPC0gMC4wNQpsMmZjIDwtIDAuNQpgYGAKCiMgQjEwLUwxMC1pbnQKCmBgYHtyIEIxMC1MMTAtaW50fQojIHNldXJhdCBvYmplY3QKbXkuc2UgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9kYXRhL0dnX2N0cmxfbHVtYl9pbnRfc2V1cmF0XzI1MDcyMy5yZHMiKQojIGNsdXN0ZXIgbGFiZWxzIGZyb20gQjEwaW50IGFuZCBMMTBpbnQKY3RybF9sdW1iX2ludF9jb21iaW5lZF9sYWJlbHMgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9hbm5vdGF0aW9ucy9jdHJsX2x1bWJfaW50X2NvbWJpbmVkX2xhYmVscy5yZHMiKQoKaWRlbnRpY2FsKGNvbG5hbWVzKG15LnNlKSwgcm93bmFtZXMoY3RybF9sdW1iX2ludF9jb21iaW5lZF9sYWJlbHMpKQpteS5zZSRhbm5vdF9zYW1wbGUgIDwtIGN0cmxfbHVtYl9pbnRfY29tYmluZWRfbGFiZWxzJGFubm90X3NhbXBsZQoKbXkuc2VAYWN0aXZlLmFzc2F5IDwtICJSTkEiCgpgYGAKCiMjIGludHJhIGNsdXN0ZXIgREUgYW5hbHlzaXMKCldlIGRvIERFIGFuYWx5c2lzIHBlciBjbHVzdGVyLCBjb250cmFzdGluZyBCMTAgYW5kIEwxMCBzYW1wbGVzOgoKYGBge3IgaW50cmEtY2x1c3Rlci1ERS1MMTAsIGV2YWw9RkFMU0V9Cm1hcmtlcnMgPC0gbGlzdCgpCm51bWJlcnMgPC0gbGlzdCgpCmNvbXBvc2l0aW9uIDwtbGlzdCgpCgpmb3IgKGkgaW4gc2VxKGxldmVscyhJZGVudHMobXkuc2UpKSkpIHsKICAjIHN1YnNldCBmb3IgaW5kaXZpZHVhbCBjbHVzdGVycwogIG1uLnNlIDwtIHN1YnNldCh4ID0gbXkuc2UsIGlkZW50cyA9IGxldmVscyhJZGVudHMobXkuc2UpKVtpXSkKICBtbi5zZSRzYW1wbGUgPC0gc3RyX2V4dHJhY3QobW4uc2Ukb3JpZy5pZGVudCwgImN0cmx8bHVtYiIpCiAgCiAgY29tcG9zaXRpb25bW2ldXSA8LSBtbi5zZVtbXV0gJT4lIAogICAgc2VsZWN0KHNhbXBsZSwgYW5ub3Rfc2FtcGxlKQogIAogIElkZW50cyhtbi5zZSkgPC0gInNhbXBsZSIKICAKICB0bXBfbWFya2VycyA8LSBGaW5kTWFya2Vycyhtbi5zZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZGVudC4xID0gImN0cmwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5wY3QgPSAwLjI1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAgMC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhdGVudC52YXJzID0gYygiQ0MuRGlmZmVyZW5jZS5zZXVyYXQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAiTUFTVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlJOQSIpCiAgIyBjZWxsIG51bWJlcnMgcGVyIHNhbXBsZQogIG51bWJlcnNbW2ldXSA8LSBkYXRhLmZyYW1lKHRhYmxlKG1uLnNlJHNhbXBsZSkpCiAgCiAgdG1wX21hcmtlcnMgPC0gdG1wX21hcmtlcnMgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oIkdlbmUuc3RhYmxlLklEIikgJT4lIAogICAgbGVmdF9qb2luKGduYW1lcykKICAKICBtYXJrZXJzW1tpXV0gPC0gdG1wX21hcmtlcnMKfQoKbmFtZXMobWFya2VycykgPC0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpCm5hbWVzKG51bWJlcnMpIDwtIHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKQpuYW1lcyhjb21wb3NpdGlvbikgPC0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpCgojIGJpbmQgbGlzdHMgaW50byBkYXRhIGZyYW1lcwpsdW1iX21hcmtlcnMgPC0gYmluZF9yb3dzKG1hcmtlcnMsIC5pZCA9ICJjbHVzdGVyIikgJT4lIAogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKSkpCmx1bWJfbnVtYmVycyA8LSBiaW5kX3Jvd3MobnVtYmVycywgLmlkID0gImNsdXN0ZXIiKSAlPiUgCiAgbXV0YXRlKGNsdXN0ZXIgPSBmYWN0b3IoY2x1c3RlciwgbGV2ZWxzID0gcGFzdGUwKCJjbC0iLCBsZXZlbHMoSWRlbnRzKG15LnNlKSkpKSkKbHVtYl9jb21wb3NpdGlvbiA8LSBiaW5kX3Jvd3MoY29tcG9zaXRpb24sIC5pZCA9ICJjbHVzdGVyIikgJT4lIAogIG11dGF0ZShjbHVzdGVyID0gZmFjdG9yKGNsdXN0ZXIsIGxldmVscyA9IHBhc3RlMCgiY2wtIiwgbGV2ZWxzKElkZW50cyhteS5zZSkpKSkpCgpzYXZlUkRTKGx1bWJfbWFya2VycywgIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX2x1bWJfaW50X21hcmtlcnMucmRzIikKc2F2ZVJEUyhsdW1iX251bWJlcnMsICJ+L3NwaW5hbF9jb3JkX3BhcGVyL2RhdGEvR2dfY3RybF9sdW1iX2ludF9udW1iZXJzLnJkcyIpCnNhdmVSRFMobHVtYl9jb21wb3NpdGlvbiwgIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX2x1bWJfaW50X2NvbXBvc2l0aW9uLnJkcyIpCmBgYAoKYGBge3J9CiMgbG9hZCB0aGUgREUgZGF0YQpsdW1iX21hcmtlcnMgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9kYXRhL0dnX2N0cmxfbHVtYl9pbnRfbWFya2Vycy5yZHMiKSAlPiUgCiAgbXV0YXRlKGNsdXN0X2lkID0gc3RyX3JlbW92ZShjbHVzdGVyLCAiXmNsLSIpKQpsdW1iX251bWJlcnMgPC0gcmVhZFJEUygifi9zcGluYWxfY29yZF9wYXBlci9kYXRhL0dnX2N0cmxfbHVtYl9pbnRfbnVtYmVycy5yZHMiKSAlPiUgCiAgbXV0YXRlKGNsdXN0X2lkID0gc3RyX3JlbW92ZShjbHVzdGVyLCAiXmNsLSIpKQpsdW1iX2NvbXBvc2l0aW9uIDwtIHJlYWRSRFMoIn4vc3BpbmFsX2NvcmRfcGFwZXIvZGF0YS9HZ19jdHJsX2x1bWJfaW50X2NvbXBvc2l0aW9uLnJkcyIpICU+JSAKICBtdXRhdGUoY2x1c3RfaWQgPSBzdHJfcmVtb3ZlKGNsdXN0ZXIsICJeY2wtIikpCmBgYAoKUGxvdCB0aGUgY2x1c3RlciBjb21wb3NpdGlvbnMgYW5kIHRoZSBudW1iZXIgb2YgbWFya2VyIGdlbmVzLgoKYGBge3J9CgpEaW1QbG90KG15LnNlLCBsYWJlbCA9IFRSVUUsIHJlZHVjdGlvbiA9ICJ0c25lIikKCmdncGxvdChkYXRhID0gbHVtYl9udW1iZXJzLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxLCBncm91cCA9IGNsdXN0ZXIsIGxhYmVsID0gRnJlcSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDMpICsKICBnZW9tX3RleHQobnVkZ2VfeSA9IDUwLCBzaXplID0gMykgKwogIGdndGl0bGUoIkNsdXN0ZXIgY29tcG9zaXRpb24gYnkgc2FtcGxlIChuQ2VsbHMpIikKCmdncGxvdChkYXRhID0gbHVtYl9tYXJrZXJzICU+JSBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSAmIGF2Z19sb2cyRkMgPiAwLjUpLCBhZXMoeCA9IGNsdXN0ZXIsIGdyb3VwID0gY2x1c3RlcikpICsKICBnZW9tX2JhcigpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDMsc2NhbGVzID0gImZyZWVfeCIpICsKICBnZ3RpdGxlKCJOdW1iZXIgb2Ygc2lnLiBERSBnZW5lcyIpCgoKCmBgYAoKIyMgREEgY2x1c3RlcnMgZnJvbSBtaWxvUgoKV2Ugc2VsZWN0IHRoZSBjbHVzdGVycyB3aXRoIHRoZSBoaWdoZXN0IGFtb3VudCBvZiBuZWlnaGJvdXJob29kcyB3aXRoIERBIG9mIGNlbGxzLiBUaG9zZSBhcmUgY2x1c3RlcnMgMyAobmV1cm9ucyksIDIxLCAyMiAoR2x5Y29nZW4gYm9keSksIGFuZCAzMCBtb3RvciBuZXVyb25zLgoKYGBge3J9CiMgdmVjdG9yIG9mIGNsdXN0ZXJzCnNlbGVjdF9jbHVzdGVycyA8LSBjKDMsMjEsMjIsMzApCgpzZWxlY3RfbHVtYl9tYXJrZXJzIDwtIGZpbHRlcihsdW1iX21hcmtlcnMsIGNsdXN0X2lkICVpbiUgc2VsZWN0X2NsdXN0ZXJzKQpzZWxlY3RfbHVtYl9udW1iZXJzIDwtIGZpbHRlcihsdW1iX251bWJlcnMsIGNsdXN0X2lkICVpbiUgc2VsZWN0X2NsdXN0ZXJzKQpzZWxlY3RfbHVtYl9jb21wb3NpdGlvbiA8LSBmaWx0ZXIobHVtYl9jb21wb3NpdGlvbiwgY2x1c3RfaWQgJWluJSBzZWxlY3RfY2x1c3RlcnMpCmBgYAoKCiMjIyBCYXJwbG90cwoKQmFycGxvdHMgc2hvd2luZyBudW1iZXIgb2YgY2VsbHMgZnJvbSBCMTAgb3IgTDEwLCBhbmQgdGhlIGNvbnRyaWJ1dGlvbnMgZnJvbSB0aGUgaW5kaXZpZHVhbCBCMTBpbnQgYW5kIEwxMGludCBjbHVzdGVyczoKCmBgYHtyIGJhcnBsb3RzLUwxMH0KZ2dwbG90KGRhdGEgPSBzZWxlY3RfbHVtYl9udW1iZXJzLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxLCBncm91cCA9IGNsdXN0ZXIsIGxhYmVsID0gRnJlcSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEpICsKICBnZW9tX3RleHQobnVkZ2VfeSA9IDEwKSArCiAgZ2d0aXRsZSgiQ2x1c3RlciBjb21wb3NpdGlvbiBieSBzYW1wbGUgKG5DZWxscykiKQoKYGBgCgpgYGB7cn0KdG9wbG90IDwtIHNlbGVjdF9sdW1iX2NvbXBvc2l0aW9uICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gc3RyX2V4dHJhY3QoYW5ub3Rfc2FtcGxlLCAiXFxkezEsMn1fLnsxfSg/PXRybHx1bWIpIikpICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gZmFjdG9yKGFubm90X3NhbXBsZSkpICU+JSAKICBncm91cF9ieShzYW1wbGUsIGNsdXN0ZXIpICU+JQogIGNvdW50KGFubm90X3NhbXBsZSkgJT4lIAogIG11dGF0ZShsYWJlbF95cG9zID0gY3Vtc3VtKG4pLSAwLjUqbikKCkJMX3NlbGVjdF9iYXJwbG90IDwtIGdncGxvdChkYXRhPXRvcGxvdCwgYWVzKHg9c2FtcGxlLCB5PW4sIGZpbGw9ZmN0X3Jldihhbm5vdF9zYW1wbGUpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyh5PWxhYmVsX3lwb3MsIGxhYmVsPWFubm90X3NhbXBsZSksIAogICAgICAgICAgICBjb2xvcj0iYmxhY2siLCBzaXplPTMuNSkgKwogIGZhY2V0X3dyYXAoImNsdXN0ZXIiLCBucm93ID0gMSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGdndGl0bGUoIkJMMTBpbnQgY2x1c3RlciBjb250cmlidXRpb25zIikKCkJMX3NlbGVjdF9iYXJwbG90CgpwZGYoIn4vc3BpbmFsX2NvcmRfcGFwZXIvZmlndXJlcy9GaWdfNF9CTDEwaW50X2hpZ2hfREFfY2x1c3RfY29udHJpYnV0aW9uLnBkZiIpCkJMX3NlbGVjdF9iYXJwbG90CmRldi5vZmYoKQoKYGBgCgoKIyMjIFZvbGNhbm9wbG90cwoKYGBge3Igdm9scGxvdHMtTDEwLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDZ9CnRvcGxvdCA8LSBzZWxlY3RfbHVtYl9tYXJrZXJzICU+JSAKICBtdXRhdGUoZ2VuZV90eXBlID0gY2FzZV93aGVuKAogICAgYXZnX2xvZzJGQyA+PSAwLjUgJiBwX3ZhbF9hZGogPD0gMC4wNSB+ICJjdHJsIiwKICAgIGF2Z19sb2cyRkMgPD0gLTAuNSAmIHBfdmFsX2FkaiA8PSAwLjA1IH4gImx1bWIiLAogICAgVFJVRSB+ICJucyIpCiAgKQoKY29scyA8LSBjKGN0cmwgPSAiYmxhY2siLAogICAgICAgICAgbHVtYiA9ICIjNDE5YzczIiwKICAgICAgICAgIG5zID0gImdyZXkiKQoKc2hhcGVzIDwtIGMoY3RybCA9IDIxLAogICAgICAgICAgICBsdW1iID0gMjEsCiAgICAgICAgICAgIG5zID0gMjApCgp2b2xwbG90IDwtIGdncGxvdChkYXRhID0gdG9wbG90LAogICAgICAgICAgICAgICAgICBhZXMoeCA9IGF2Z19sb2cyRkMsCiAgICAgICAgICAgICAgICAgICAgICB5ID0gLWxvZzEwKHBfdmFsX2FkaiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IEdlbmUubmFtZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZ2VuZV90eXBlLAogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBnZW5lX3R5cGUKICAgICAgICAgICAgICAgICAgKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKHAuYWRqKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLWwyZmMsbDJmYyksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29scykgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBzaGFwZXMpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEpICsKICB5bGFiKCItbG9nMTAocGFkaikiKSArCiAgdGhlbWVfYncoKSsKICBnZ3RpdGxlKCJTaWcuIG1hcmtlciBnZW5lcyIpCgp2b2xwbG90CiMgZ2dwbG90bHkodm9scGxvdCwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSA2MDApCgpgYGAKClBsb3RzIHdpdGhvdXQgSE9YIGFuZCBtaXRvY2hvbmRyaWFsIGdlbmVzOgoKYGBge3IsICBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDZ9CiMgZmlsdGVyIG91dCBIT1ggYW5kIE1UIGdlbmVzCnRvcGxvdF9ub210IDwtIHRvcGxvdCAlPiUgCiAgZmlsdGVyKCFncmVwbCgiXkhPWCIsIEdlbmUubmFtZSkpICU+JSAKICBmaWx0ZXIoIUdlbmUuc3RhYmxlLklEICVpbiUgbXQpCgp2b2xwbG90X25vbXQgPC0gZ2dwbG90KGRhdGEgPSB0b3Bsb3Rfbm9tdCwKICAgICAgICAgICAgICAgICAgYWVzKHggPSBhdmdfbG9nMkZDLAogICAgICAgICAgICAgICAgICAgICAgeSA9IC1sb2cxMChwX3ZhbF9hZGopLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBHZW5lLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGdlbmVfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZ2VuZV90eXBlCiAgICAgICAgICAgICAgICAgICkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMChwLmFkaiksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC1sMmZjLGwyZmMpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gc2hhcGVzKSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAxKSArCiAgeWxhYigiLWxvZzEwKHBhZGopIikgKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMgKHdpdGhvdXQgTVQgYW5kIEhPWCBnZW5lcyIpCgp2b2xwbG90X25vbXQKIyBnZ3Bsb3RseSh2b2xwbG90X25vbXQsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gNjAwKQoKYGBgCgpgYGB7cn0Kdm9scGxvdF9ub210ICsKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBpZmVsc2UoZ2VuZV90eXBlID09ICducycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5lLm5hbWUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpCmBgYAoKCiMjIyBObyBNTiBERSBnZW5lcwoKQ2x1c3RlciAzMCAoQ29uc2lzdGluZyBvZiAxNjEgQjEwIHZzIDEzIEwxMCBjZWxscykgc2hvd3Mgbm8gTU4gcmVsYXRlZCBtYXJrZXJzLiBTZWVtaW5nbHksIHRob3NlIDEzIGNlbGxzIGFyZSBpbmRlZWQgbW90b3IgbmV1cm9ucy4gVGhpcyBpcyBzdXBwb3J0ZWQgYnkgdGhlIGZhY3Qgb2YgdGhlaXIgZXhwcmVzc2lvbiBvZiBUVUJCMywgRk9YUDEsIGFuZCBTTEMxOEEzLgoKYGBge3J9CiMgTW90b3IgbmV1cm9uIGNsdXN0ZXIKbW4uc2UgPC0gc3Vic2V0KHggPSBteS5zZSwgaWRlbnRzID0gMzApCm1uLnNlJHNhbXBsZSA8LSBzdHJfZXh0cmFjdChtbi5zZSRvcmlnLmlkZW50LCAiY3RybHxsdW1iIikKCm1uLnNlQGFjdGl2ZS5hc3NheSA8LSAiaW50ZWdyYXRlZCIKCm1uX21hcmtlcnMgPC0gZ25hbWVzW2dyZXBsKCJUVUJCM3xGT1hQMXxTTEMxOEEzIiwgZ25hbWVzJEdlbmUubmFtZSksXQptbl9tYXJrZXJzCgpWbG5QbG90KG1uLnNlLCBncm91cC5ieSA9ICJzYW1wbGUiLCBtbl9tYXJrZXJzJEdlbmUuc3RhYmxlLklELCBjb2xzID0gYygiZGFya2dyZXkiLCAiIzQxOWM3MyIpKQpgYGAKCiMjIExvdyBEQSBjbHVzdGVycyBmcm9tIG1pbG9SCgpJbiBjb250cmFzdCB0byB0aGUgY2x1c3RlcnMgYWJvdmUsIHdlIG5vdyBzZWxlY3QgY2x1c3RlcnMgMTcsIDE4LCBhbmQgMTkuIFRoZSBzaG93IGEgdmVyeSBsb3cgYW1vdW50IG9mIERBIG5laWdoYm91cmhvb2RzLCBhcmUgb2Ygc2ltaWxhciBzaXplIGFuZCByZXByZXNlbnQgbmV1cm9uYWwsIE1GT0wsIGFuZCBOUEMgcG9wdWxhdGlvbnMuCgpgYGB7cn0KIyB2ZWN0b3Igb2YgTUZPTCBjbHVzdGVycwpsb3dfY2x1c3RlcnMgPC0gYygxNywgMTgsIDE5KQoKbG93X2x1bWJfbWFya2VycyA8LSBmaWx0ZXIobHVtYl9tYXJrZXJzLCBjbHVzdF9pZCAlaW4lIGxvd19jbHVzdGVycykKbG93X2x1bWJfbnVtYmVycyA8LSBmaWx0ZXIobHVtYl9udW1iZXJzLCBjbHVzdF9pZCAlaW4lIGxvd19jbHVzdGVycykKbG93X2x1bWJfY29tcG9zaXRpb24gPC0gZmlsdGVyKGx1bWJfY29tcG9zaXRpb24sIGNsdXN0X2lkICVpbiUgbG93X2NsdXN0ZXJzKQpgYGAKCgojIyMgQmFycGxvdHMKCkJhcnBsb3RzIHNob3dpbmcgbnVtYmVyIG9mIGNlbGxzIGZyb20gQjEwIG9yIEwxMCwgYW5kIHRoZSBjb250cmlidXRpb25zIGZyb20gdGhlIGluZGl2aWR1YWwgQjEwaW50IGFuZCBMMTBpbnQgY2x1c3RlcnM6CgpgYGB7ciBiYXJwbG90cy1MMTAtTUZPTH0KZ2dwbG90KGRhdGEgPSBsb3dfbHVtYl9udW1iZXJzLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxLCBncm91cCA9IGNsdXN0ZXIsIGxhYmVsID0gRnJlcSkpICsKICBnZW9tX2NvbCgpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEpICsKICBnZW9tX3RleHQobnVkZ2VfeSA9IDEwKSArCiAgZ2d0aXRsZSgiQ2x1c3RlciBjb21wb3NpdGlvbiBieSBzYW1wbGUgKG5DZWxscykiKQoKYGBgCgpgYGB7cn0KdG9wbG90IDwtIGxvd19sdW1iX2NvbXBvc2l0aW9uICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gc3RyX2V4dHJhY3QoYW5ub3Rfc2FtcGxlLCAiXFxkezEsMn1fLnsxfSg/PXRybHx1bWIpIikpICU+JSAKICBtdXRhdGUoYW5ub3Rfc2FtcGxlID0gZmFjdG9yKGFubm90X3NhbXBsZSkpICU+JSAKICBncm91cF9ieShzYW1wbGUsIGNsdXN0ZXIpICU+JQogIGNvdW50KGFubm90X3NhbXBsZSkgJT4lIAogIG11dGF0ZShsYWJlbF95cG9zID0gY3Vtc3VtKG4pLSAwLjUqbikKCkJMX2xvd19iYXJwbG90IDwtIGdncGxvdChkYXRhPXRvcGxvdCwgYWVzKHg9c2FtcGxlLCB5PW4sIGZpbGw9ZmN0X3Jldihhbm5vdF9zYW1wbGUpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KGFlcyh5PWxhYmVsX3lwb3MsIGxhYmVsPWFubm90X3NhbXBsZSksIAogICAgICAgICAgICBjb2xvcj0iYmxhY2siLCBzaXplPTMuNSkgKwogIGZhY2V0X3dyYXAoImNsdXN0ZXIiLCBucm93ID0gMSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGdndGl0bGUoIkZyb20gd2hpY2ggY2x1c3RlcnMgZG8gY2VsbHMgY29tZT8iKQoKQkxfbG93X2JhcnBsb3QKCnBkZigifi9zcGluYWxfY29yZF9wYXBlci9maWd1cmVzL0ZpZ180X0JMMTBpbnRfbG93X0RBX2NsdXN0X2NvbnRyaWJ1dGlvbi5wZGYiKQpCTF9sb3dfYmFycGxvdApkZXYub2ZmKCkKCmBgYAoKIyMjIFZvbGNhbm9wbG90cwoKYGBge3Igdm9scGxvdHMtTDEwX01GT0wsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNn0KdG9wbG90IDwtIGxvd19sdW1iX21hcmtlcnMgJT4lIAogIG11dGF0ZShnZW5lX3R5cGUgPSBjYXNlX3doZW4oCiAgICBhdmdfbG9nMkZDID49IDAuNSAmIHBfdmFsX2FkaiA8PSAwLjA1IH4gImN0cmwiLAogICAgYXZnX2xvZzJGQyA8PSAtMC41ICYgcF92YWxfYWRqIDw9IDAuMDUgfiAibHVtYiIsCiAgICBUUlVFIH4gIm5zIikKICApCgpjb2xzIDwtIGMoY3RybCA9ICJibGFjayIsCiAgICAgICAgICBsdW1iID0gIiM0MTljNzMiLAogICAgICAgICAgbnMgPSAiZ3JleSIpCgpzaGFwZXMgPC0gYyhjdHJsID0gMjEsCiAgICAgICAgICAgIGx1bWIgPSAyMSwKICAgICAgICAgICAgbnMgPSAyMCkKCnZvbHBsb3QgPC0gZ2dwbG90KGRhdGEgPSB0b3Bsb3QsCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gYXZnX2xvZzJGQywKICAgICAgICAgICAgICAgICAgICAgIHkgPSAtbG9nMTAocF92YWxfYWRqKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gR2VuZS5uYW1lLAogICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBnZW5lX3R5cGUsCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGdlbmVfdHlwZQogICAgICAgICAgICAgICAgICApKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAocC5hZGopLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtbDJmYyxsMmZjKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xzKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IHNoYXBlcykgKwogIHhsaW0oYygtMy41LCAzLjUpKSArCiAgZmFjZXRfd3JhcCgiY2x1c3RlciIsIG5yb3cgPSAxKSArCiAgeWxhYigiLWxvZzEwKHBhZGopIikgKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMiKQoKdm9scGxvdAojIGdncGxvdGx5KHZvbHBsb3QsIHdpZHRoID0gODAwLCBoZWlnaHQgPSA1MDApCgpgYGAKClBsb3RzIHdpdGhvdXQgSE9YIGFuZCBtaXRvY2hvbmRyaWFsIGdlbmVzOgoKYGBge3IsICBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDZ9CiMgZmlsdGVyIG91dCBIT1ggYW5kIE1UIGdlbmVzCnRvcGxvdF9ub210IDwtIHRvcGxvdCAlPiUgCiAgZmlsdGVyKCFncmVwbCgiXkhPWCIsIEdlbmUubmFtZSkpICU+JSAKICBmaWx0ZXIoIUdlbmUuc3RhYmxlLklEICVpbiUgbXQpCgp2b2xwbG90X25vbXQgPC0gZ2dwbG90KGRhdGEgPSB0b3Bsb3Rfbm9tdCwKICAgICAgICAgICAgICAgICAgYWVzKHggPSBhdmdfbG9nMkZDLAogICAgICAgICAgICAgICAgICAgICAgeSA9IC1sb2cxMChwX3ZhbF9hZGopLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBHZW5lLm5hbWUsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGdlbmVfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZ2VuZV90eXBlCiAgICAgICAgICAgICAgICAgICkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMChwLmFkaiksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC1sMmZjLGwyZmMpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gc2hhcGVzKSArCiAgeGxpbShjKC0xLjUsIDEuNSkpICsKICBmYWNldF93cmFwKCJjbHVzdGVyIiwgbnJvdyA9IDEsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgeWxhYigiLWxvZzEwKHBhZGopIikgKwogIHRoZW1lX2J3KCkrCiAgZ2d0aXRsZSgiU2lnLiBtYXJrZXIgZ2VuZXMgKHdpdGhvdXQgTVQgYW5kIEhPWCBnZW5lcykiKQoKdm9scGxvdF9ub210CiMgZ2dwbG90bHkodm9scGxvdF9ub210LCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gNTAwKQoKYGBgCgpgYGB7cn0KcDEgPC0gdm9scGxvdCArCiAgICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gaWZlbHNlKGdlbmVfdHlwZSA9PSAnbnMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR2VuZS5uYW1lKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKQoKcDIgPC0gdm9scGxvdF9ub210ICsKICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBpZmVsc2UoZ2VuZV90eXBlID09ICducycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5lLm5hbWUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpCgpwMQpwMgoKcGRmKCJ+L3NwaW5hbF9jb3JkX3BhcGVyL2ZpZ3VyZXMvRmlnXzRfQkwxMGludF9sb3dfREFfdm9scGxvdHMucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQpwMQpwMgpkZXYub2ZmKCkKCmBgYAoKYGBge3J9CiMgRGF0ZSBhbmQgdGltZSBvZiBSZW5kZXJpbmcKU3lzLnRpbWUoKQoKc2Vzc2lvbkluZm8oKQpgYGA=